It is possible to define a field within a class (or structure) whose value is the result of a LINQ query. To do so, however, you cannot make use of implicit typing (as the var keyword cannot be used for fields) and the target of the LINQ query cannot be instance level data, therefore it must be static. Given these limitations, you will seldom need to author code like the following:
class LINQBasedFieldsAreClunky { private static string[] currentVideoGames = {"Morrowind", "Uncharted 2", "Fallout 3", "Daxter", "System Shock 2"}; // Can't use implicit typing here! Must know type of subset! private IEnumerable<string> subset = from g in currentVideoGames where g.Contains(" ") orderby g select g; public void PrintGames() { foreach (var item in subset) { Console.WriteLine(item); } } }
More often than not, LINQ queries are defined within the scope of a method or property. Moreover, to simplify your programming, the variable used to hold the result set will be stored in an implicitly typed local variable using the var keyword. Now, recall from Chapter 3 that implicitly typed variables cannot be used to define parameters, return values, or fields of a class or structure.
Given this point, you may wonder exactly how you could return a query result to an external caller. The answer is, it depends. If you have a result set consisting of strongly typed data such as an array of strings or a List<T> of Cars, you could abandon the use of the var keyword and use a proper IEnumerable<T> or IEnumerable type (again, as IEnumerable<T> extends IEnumerable). Consider the following example for a new Console Application named LinqRetValues:
class Program { static void Main(string[] args) { Console.WriteLine("***** LINQ Transformations *****\n"); IEnumerable<string> subset = GetStringSubset(); foreach (string item in subset) { Console.WriteLine(item); } Console.ReadLine(); } static IEnumerable<string> GetStringSubset() { string[] colors = {"Light Red", "Green", "Yellow", "Dark Red", "Red", "Purple"}; // Note subset is an IEnumerable<string> compatible object. IEnumerable<string> theRedColors = from c in colors where c.Contains("Red") select c; return theRedColors; } }
Light Red Dark Red Red
This example works as expected, only because the return value of the GetStringSubset() and the LINQ query within this method has been strongly typed. If you used the var keyword to define the subset variable, it would be permissible to return the value only if the method is still prototyped to return IEnumerable<string> (and if the implicitly typed local variable is in fact compatible with the specified return type).
Because it is a tad bit inconvenient to operate on IEnumerable<T>, you could make use of immediate execution. For example, rather than returning IEnumerable<string>, you could simply return a string[], provided that you transform the sequence to a strongly typed array. Consider this new method of the Program class which does this very thing:
static string[] GetStringSubsetAsArray() { string[] colors = {"Light Red", "Green", "Yellow", "Dark Red", "Red", "Purple"}; var theRedColors = from c in colors where c.Contains("Red") select c; // Map results into an array. return theRedColors.ToArray(); }
With this, the caller can be blissfully unaware that their result came from a LINQ query, and simply work with the array of strings as expected. For an example, see the following code:
foreach (string item in GetStringSubsetAsArray()) { Console.WriteLine(item); }
Immediate execution is also critical when attempting to return to the caller the results of a LINQ projection. You’ll examine this topic a bit later in the chapter. However, next up, let’s look at how to apply LINQ queries to generic and nongeneric collection objects.
Source Code The LinqRetValues project can be found under the Chapter 13 subdirectory.